package com.aliothservice.catfish.message;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.aliothservice.catfish.SessionManager;
import com.aliothservice.catfish.message.data.Message;
import com.aliothservice.catfish.message.data.MessageDataManager;
import com.aliothservice.catfish.message.data.MessageHub;
import com.aliothservice.catfish.message.request.DeleteMessagesRequest;
import com.aliothservice.catfish.message.request.ListMessagesRequest;
import com.aliothservice.catfish.message.request.ReadMessagesRequest;
import com.aliothservice.catfish.message.request.UnreadMessageCountRequest;

public class MessageController {
	
	public static final boolean isRunningOnProduction = true;
	
	public Object listMessages(ListMessagesRequest req) {
		Map<String, String> map = new HashMap<String, String>();
		
		// validate token
		String phoneNumber = (String)sessionManager.valueForRestToken(req.getToken());
		if (null == phoneNumber) {
			map.put("errorCode", "300");
			map.put("errorMessage", "token expired");
			return map;
		}
		
		// set up pageable
		int page;
		if (null != req.getPage()) {
			page = (req.getPage().intValue()>=0) ? req.getPage().intValue() : 0;
		} else {
			page = 0;
		}
		int size;
		if (null != req.getSize()) {
			size = (req.getSize().intValue()<100) ? req.getSize().intValue() : 100;
		} else {
			size = 100;
		}
		
		// compose result object
		Map<String, List<Map<String, String>>> resMap = new HashMap<String, List<Map<String, String>>>();
		
		// locate user's message hub and compose response
		int padding = 0;
		MessageHub hub = messageDataManager.findMessageHubByPhoneNumber(phoneNumber);
		if (null != hub) {
			if ((null!=hub.getUnreadMessages()) && (hub.getUnreadMessages().size()>0)) {
				if (hub.getUnreadMessages().size() > page*size) {
					DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
					List<Map<String, String>> unreadMessageList = new ArrayList<Map<String, String>>();
					for (int step=page*size; step<hub.getUnreadMessages().size()&&padding<size; step++) {
						Map<String, String> messageMap = new HashMap<String, String>();
						Message message = hub.getUnreadMessages().get(step);
						messageToMap(messageMap, message, formatter);
						unreadMessageList.add(messageMap);
						padding++;
					}
					resMap.put("unread", unreadMessageList);
					if (unreadMessageList.size() >= size) {
						return resMap;
					}
				}
			}
			if ((null!=hub.getReadMessages()) && (hub.getReadMessages().size()>0)) {
				if (padding > 0) {
					DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
					List<Map<String, String>> readMessageList = new ArrayList<Map<String, String>>();
					for (int step=0; step<hub.getReadMessages().size()&&step<(size-padding); step++) {
						Map<String, String> messageMap = new HashMap<String, String>();
						Message message = hub.getReadMessages().get(step);
						messageToMap(messageMap, message, formatter);
						readMessageList.add(messageMap);
					}
					resMap.put("read", readMessageList);
				} else {
					if (hub.getReadMessages().size() > page*size) {
						DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
						List<Map<String, String>> readMessageList = new ArrayList<Map<String, String>>();
						for (int step=page*size; step<hub.getReadMessages().size()&&padding<size; step++) {
							Map<String, String> messageMap = new HashMap<String, String>();
							Message message = hub.getReadMessages().get(step);
							messageToMap(messageMap, message, formatter);
							readMessageList.add(messageMap);
							padding++;
						}
						resMap.put("read", readMessageList);
					}
				}
			}
		}
		
		// reset token expiration
		sessionManager.resetRestTokenExpiration(phoneNumber, req.getToken());

		return resMap;
	}
	
	public Map<String, String> unreadMessageCount(UnreadMessageCountRequest req) {
		Map<String, String> map = new HashMap<String, String>();
		
		// validate token
		String phoneNumber = (String)sessionManager.valueForRestToken(req.getToken());
		if (null == phoneNumber) {
			map.put("errorCode", "300");
			map.put("errorMessage", "token expired");
			return map;
		}
		
		// locate message hub
		MessageHub hub = messageDataManager.findMessageHubByPhoneNumber(phoneNumber);
		if (null == hub) {
			map.put("count", "0");
			return map;
		}
		map.put("count", String.valueOf(hub.getUnreadMessages().size()));
		
		return map;
	}
	
	public Map<String, String> readMessages(ReadMessagesRequest req) {
		Map<String, String> map = new HashMap<String, String>();
		
		// check parameters
		if ((null==req.getIdList()) || (0==req.getIdList().size())) {
			map.put("errorCode", "400");
			map.put("errorMessage", "missing parameters");
			return map;
		}

		// validate token
		String phoneNumber = (String)sessionManager.valueForRestToken(req.getToken());
		if (null == phoneNumber) {
			map.put("errorCode", "300");
			map.put("errorMessage", "token expired");
			return map;
		}
		
		messageDataManager.readMessages(phoneNumber, req.getIdList());
		
		// reset token expiration
		sessionManager.resetRestTokenExpiration(phoneNumber, req.getToken());
		
		return map;
	}
	
	public Map<String, String> deleteMessages(DeleteMessagesRequest req) {
		Map<String, String> map = new HashMap<String, String>();
		
		// check parameters
		if ((null==req.getIdList()) || (0==req.getIdList().size())) {
			map.put("errorCode", "400");
			map.put("errorMessage", "missing parameters");
			return map;
		}

		// validate token
		String phoneNumber = (String)sessionManager.valueForRestToken(req.getToken());
		if (null == phoneNumber) {
			map.put("errorCode", "300");
			map.put("errorMessage", "token expired");
			return map;
		}
		
		// perform deletion
		if (!messageDataManager.deleteMessages(phoneNumber, req.getIdList())) {
			map.put("errorCode", "500");
			map.put("errorMessage", "failed to delete");
			return map;
		}
		
		// reset token expiration
		sessionManager.resetRestTokenExpiration(phoneNumber, req.getToken());
		
		return map;
	}
	
	public void postMessage(Message message, String phoneNumber) {
		if (logger.isDebugEnabled()) {
			logger.debug("new message sent to " + phoneNumber);
		}
		messageDataManager.postMessage(message, phoneNumber);
	}
	
	protected void messageToMap(Map<String, String> messageMap, Message message, DateFormat formatter) {
		messageMap.put("id", message.getId());
		messageMap.put("title", message.getTitle());
		messageMap.put("content", message.getContent());
		messageMap.put("date", formatter.format(message.getDate()));
		messageMap.put("payload", message.getPayload());
		messageMap.put("flag", message.getFlag());
		messageMap.put("sourceModule", message.getSourceModule());
		messageMap.put("sourceEvent", message.getSourceEvent());
	}
	
	@Autowired
	private MessageDataManager messageDataManager;

	@Autowired
	private SessionManager sessionManager;
	
	private static final Logger logger = LoggerFactory.getLogger(MessageController.class);
	
}
